package net.avcompris.binding;

import static com.avcompris.util.ExceptionUtils.nonNullArgument;
import net.avcompris.binding.annotation.XPath;

import com.avcompris.common.annotation.Nullable;

/**
 * an object to hold binding configuration for a given class. Similar to
 * declare an {@link XPath}-annotation for the class. 
 * 
 * @author David Andrianavalontsalama
 */
public class ClassBinding {

	/**
	 * constructor for all classes: <tt>className</tt> is <tt>"*"</tt> (= all).
	 */
	public ClassBinding(@Nullable final BindConfiguration configuration) {

		this(configuration, "*");
	}

	/**
	 * constructor with a class already loaded.
	 */
	public ClassBinding(
			@Nullable final BindConfiguration configuration,
			final Class<?> clazz) {

		this.configuration = configuration;
		this.clazz = nonNullArgument(clazz, "clazz");
		this.className = clazz.getName();
	}

	/**
	 * constructor with the name of a class only.
	 */
	public ClassBinding(
			@Nullable final BindConfiguration configuration,
			final String className) {

		this.configuration = configuration;
		this.clazz = null;
		this.className = nonNullArgument(className, "className");
	}

	private final BindConfiguration configuration;

	@Nullable
	private final Class<?> clazz;

	private final String className;

	/**
	 * get the binding configuration.
	 */
	@Nullable
	public BindConfiguration getConfiguration() {

		return configuration;
	}

	/**
	 * get the name of the class.
	 */
	public String getBindingClassName() {

		return className;
	}

	/**
	 * get the class itself, through a {@link ClassLoader}.
	 * If <tt>className</tt> was <tt>"*"</tt> (= all), this method returns
	 * <tt>null</tt>.
	 */
	@Nullable
	public Class<?> getBindingClass(final ClassLoader classLoader) throws ClassNotFoundException {

		nonNullArgument(classLoader, "classLoader");

		if (clazz != null) {

			return clazz;
		}

		if ("*".equals(className)) {

			return null;
		}

		return classLoader.loadClass(className);
	}

	/**
	 * get the class itself, through the default {@link ClassLoader}, that is,
	 * the one from the current {@link Thread}.
	 * If <tt>className</tt> was <tt>"*"</tt> (= all), this method returns
	 * <tt>null</tt>.
	 */
	public Class<?> getBindingClass() throws ClassNotFoundException {

		final ClassLoader classLoader = Thread.currentThread()
				.getContextClassLoader();

		return getBindingClass(classLoader);
	}
}
